﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Xml.Linq;
using Dapper;
using Gallery.DAL.Entities;

namespace Gallery.DAL.Repositories
{
    public class PictureRepository
    {
        public static string PathToXml
        {
            get
            {
                return HttpContext.Current.Server.MapPath(WebConfigurationManager.AppSettings["pathToXml"].ToString());
            }
        }

        public static string PathToFiles
        {
            get
            {
                return HttpContext.Current.Server.MapPath(WebConfigurationManager.AppSettings["pathToFiles"].ToString());
            }
        }
                       
        internal static Guid InsertId(Picture p)
        {
            XDocument document = XDocument.Load(PathToXml);
            
            var guid = Guid.NewGuid();
            XElement element = new XElement("image",
                                            new XElement("PictureId", guid),
                                            new XElement("FileName", p.FileName),
                                            new XElement("PictureName", p.PictureName),
                                            new XElement("AuthorAge", p.AuthorAge),
                                            new XElement("DateCreated", p.DateCreated == null ? "" : p.DateCreated.Value.ToShortDateString()),
                                            new XElement("SequenceNumber", (MaxNumber() + 1).ToString())
                                            );
            document.Root.Add(element);
            document.Save(PathToXml);

            return guid;
        }

        internal static void Update(String[] p)
        {
            XDocument document = XDocument.Load(PathToXml);

            var elements = (from x in document.Root.Elements("image")
                            where x.Element("PictureId").Value == p[0]
                            select x).Elements().ToList();

            
            for (int i = 0; i < elements.Count; i++)
            {
                if (elements[i].Name == "PictureId")
                    elements[i].Value = p[0];
                else if (elements[i].Name == "FileName")
                    elements[i].Value = p[1];
                else if (elements[i].Name == "PictureName")
                    elements[i].Value = p[2];
                else if (elements[i].Name == "AuthorAge")
                    elements[i].Value = p[3];
                else if (elements[i].Name == "DateCreated")
                    elements[i].Value = p[4];
            }

            document.Save(PathToXml);
        }

        internal static void Down(string id)
        {
            XDocument document = XDocument.Load(PathToXml);

            var elements = (from x in document.Root.Elements("image")
                            where x.Element("PictureId").Value == id
                            select x).Elements("SequenceNumber").ToList();

            int number = Convert.ToInt32(elements[0].Value);
            
            var elementsAfter = (from x in document.Root.Elements("image")
                                 where Convert.ToInt32(x.Element("SequenceNumber").Value) == number + 1
                                 select x).Elements("SequenceNumber").ToList();

            elements[0].Value = (number + 1).ToString();
            elementsAfter[0].Value = number.ToString();

            document.Save(PathToXml);
        }

        internal static void Up(string id)
        {
            XDocument document = XDocument.Load(PathToXml);

            var elements = (from x in document.Root.Elements("image")
                            where x.Element("PictureId").Value == id
                            select x).Elements("SequenceNumber").ToList();
            
            int number = Convert.ToInt32(elements[0].Value);
            
            var elementsBefore = (from x in document.Root.Elements("image")
                                 where Convert.ToInt32(x.Element("SequenceNumber").Value) == number - 1
                                  select x).Elements("SequenceNumber").ToList();

            elements[0].Value = (number - 1).ToString();
            elementsBefore[0].Value = number.ToString();

            document.Save(PathToXml);
        }
        
        internal static void SetSequenceNumber()
        {
            XDocument document = XDocument.Load(PathToXml);

            var nodes = (from x in document.Root.Elements("image")
                            select x).ToList();

            for (int i = 0; i < nodes.Count; i++)
            {
                XElement el = new XElement("SequenceNumber", (i + 1).ToString());
                nodes[i].Add(el);
            }

            document.Save(PathToXml);
        }

        internal static void Delete(string pictureId)
        {
            XDocument document = XDocument.Load(PathToXml);

            var elements = (from x in document.Root.Elements("image")
                            where x.Element("PictureId").Value == pictureId
                            select x).Elements("SequenceNumber").ToList();
            int number = Convert.ToInt32(elements[0].Value);

            (from x in document.Root.Elements("image")
                where x.Element("PictureId").Value == pictureId
                select x).Remove();


            var elementsAfter = (from x in document.Root.Elements("image")
                                 where Convert.ToInt32(x.Element("SequenceNumber").Value) > number
                                 select x).Elements("SequenceNumber").ToList();
            for (int i = 0; i < elementsAfter.Count; i++)
            {
                elementsAfter[i].Value = (Convert.ToInt32(elementsAfter[i].Value) - 1).ToString();
            }

            document.Save(PathToXml);

            DeleteFile(pictureId);
        }

        private static void DeleteFile(String pictureId)
        {
            //String[] picList = Directory.GetFiles(PathToFiles, "*.jpg");
            String[] picList = Directory.GetFiles(PathToFiles);
            foreach (String f in picList)
            {
                if (f.Contains(pictureId))
                {
                    File.Delete(f);
                }
            }
        }

        internal static IEnumerable<Picture> FindAll()
        {
            XElement result = RequestHandler.ProcessXML(PathToXml);
            return GoLinqToXml(result);
        }


        private static IEnumerable<Picture> GoLinqToXml(XElement xml)
        {
            List<Picture> list = new List<Picture>(); ;
            var images = xml.Elements("image");

            foreach (XElement node in images)
            {
                Guid pid = new Guid(node.Element("PictureId").Value);
                String fileName = node.Element("FileName").Value;
                String pictureName = node.Element("PictureName").Value;
                Int32? authorAge = node.Element("AuthorAge").Value.Trim() == "" ? null : (Int32?)Convert.ToInt32(node.Element("AuthorAge").Value);
                var date = node.Element("DateCreated").Value.Trim();

                DateTime? dateCreated = date == "" ? null : (DateTime?)Convert.ToDateTime(date);
                int sequenceNumber = Convert.ToInt32(node.Element("SequenceNumber").Value);

                Picture p = new Picture(pid, fileName, pictureName, authorAge, dateCreated, sequenceNumber);
                list.Add(p);
            }
            return list.OrderBy(l => l.SequenceNumber).ToList();
        }

        internal static int MaxNumber()
        {
            XDocument document = XDocument.Load(PathToXml);

            int maxNumber = document.Descendants("image").Count();
            return maxNumber;
        }
        
    }

    public class RequestHandler
    {
        public static XElement ProcessXML(String PathToXml)
        {
            StreamReader reader = new StreamReader(PathToXml);
            XElement result = XElement.Load(reader.BaseStream);

            reader.Close();
            reader.Dispose();

            return result;
        }
    }
}
